package com.xhj.mybatis.session.defaults;


import com.xhj.mybatis.executor.Executor;
import com.xhj.mybatis.mapping.MappedStatement;
import com.xhj.mybatis.reflection.ParamNameResolver;
import com.xhj.mybatis.session.Configuration;
import com.xhj.mybatis.session.ResultHandler;
import com.xhj.mybatis.session.RowBounds;
import com.xhj.mybatis.session.SqlSession;

import java.util.List;

/**
 * DefaultSqlSession
 *
 * @author XJks
 * @description 默认的SqlSession实现类
 */
public class DefaultSqlSession implements SqlSession {

    /**
     * 全局配置对象
     */
    private Configuration configuration;

    /**
     * 执行器对象，负责具体的 SQL 执行、事务管理等操作
     */
    private Executor executor;

    /**
     * 是否自动提交事务，true 表示每次操作后自动提交，false 需要手动提交
     */
    private final boolean autoCommit;

    /**
     * 标记当前会话是否有未提交的更改（如 insert、update、delete 操作产生的脏数据）。
     * true 表示有脏数据（需要 commit 或 rollback），false 表示没有更改或已提交，主要用于判断是否需要提交或回滚事务。
     */
    private boolean dirty;

    public DefaultSqlSession(Configuration configuration, Executor executor) {
        this(configuration, executor, false);
    }

    public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
        this.configuration = configuration;
        this.executor = executor;
        this.dirty = false;
        this.autoCommit = autoCommit;
    }

    @Override
    public <T> T selectOne(String statement) {
        return selectOne(statement, null);
    }

    @Override
    public <T> T selectOne(String statement, Object parameter) {
        List<T> list = selectList(statement, parameter);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new RuntimeException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
            return null;
        }
    }

    @Override
    public <E> List<E> selectList(String statement) {
        return selectList(statement, null);
    }

    @Override
    public <E> List<E> selectList(String statement, Object parameter) {
        return this.selectList(statement, parameter, RowBounds.DEFAULT);
    }

    @Override
    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
    }

    /**
     * 泛型私有方法，查询数据库并返回结果列表
     *
     * @param statement SQL 语句的唯一标识符
     * @param parameter 查询参数
     * @param rowBounds 分页参数
     * @param handler   结果处理器
     * @param <E>       结果类型
     * @return 结果列表
     */
    private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
        try {
            // 通过 statement id 从配置中获取对应的 MappedStatement（SQL 映射信息）
            MappedStatement ms = configuration.getMappedStatement(statement);
            // 调用执行器 executor 的 query 方法，执行查询，返回结果列表。
            // wrapCollection(parameter) 用于将参数包装成 Map，如果是集合或数组。
            // rowBounds 用于分页。
            // handler 是结果处理器，可以自定义处理结果。
            return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
        } catch (Exception e) {
            // 捕获异常，抛出运行时异常，包含详细错误信息
            throw new RuntimeException("Error querying database.  Cause: " + e, e);
        }
    }

    /**
     * 包装集合参数
     *
     * @param object 参数对象
     * @return 包装后的对象
     */
    private Object wrapCollection(final Object object) {
        return ParamNameResolver.wrapToMapIfCollection(object, null);
    }

    @Override
    public int insert(String statement) {
        return insert(statement, null);
    }

    @Override
    public int insert(String statement, Object parameter) {
        return update(statement, parameter);
    }

    @Override
    public int update(String statement) {
        return update(statement, null);
    }

    @Override
    public int update(String statement, Object parameter) {
        try {
            MappedStatement mappedStatement = configuration.getMappedStatement(statement);
            return executor.update(mappedStatement, parameter);
        } catch (Exception e) {
            throw new RuntimeException("Error updating database.  Cause: " + e);
        }
    }

    @Override
    public int delete(String statement) {
        return update(statement, null);
    }

    @Override
    public int delete(String statement, Object parameter) {
        return update(statement, parameter);
    }

    @Override
    public void commit() {
        commit(false);
    }

    @Override
    public void commit(boolean force) {
        try {
            // 调用执行器的 commit 方法，提交事务
            executor.commit(isCommitOrRollbackRequired(force));
            // 提交后，将 dirty 标记设为 false，表示没有未提交的更改
            dirty = false;
        } catch (Exception e) {
            // 如果提交过程中发生异常，包装并抛出 MyBatis 的异常，方便定位问题
            throw new RuntimeException("Error committing transaction.  Cause: " + e, e);
        }
    }

    @Override
    public void rollback() {
        rollback(false);
    }

    @Override
    public void rollback(boolean force) {
        try {
            // 调用执行器的 rollback 方法，回滚事务
            executor.rollback(isCommitOrRollbackRequired(force));
            // 回滚后，将 dirty 标记设为 false，表示没有未提交的更改
            dirty = false;
        } catch (Exception e) {
            // 如果回滚过程中发生异常，包装并抛出 MyBatis 的异常，方便定位问题
            throw new RuntimeException("Error rolling back transaction.  Cause: " + e, e);
        }
    }

    @Override
    public void close() {
        // 关闭底层执行器（Executor），并根据是否需要提交/回滚来处理事务
        executor.close(isCommitOrRollbackRequired(false));
        // todo:源码中还存在关闭所有已注册的游标（Cursor）逻辑
        // 将 dirty 标记设为 false，表示没有未提交的更改
        dirty = false;
    }

    @Override
    public void clearCache() {
        executor.clearLocalCache();
    }

    /**
     * 判断是否需要提交或回滚事务的方法
     *
     * @param force 是否强制提交/回滚
     * @return 是否需要提交或回滚
     */
    private boolean isCommitOrRollbackRequired(boolean force) {
        /**
         * TODO:
         *  逻辑说明：
         *      1. !autoCommit && dirty：如果不是自动提交模式（autoCommit 为 false）且有未提交的更改（dirty 为 true），则需要提交或回滚。
         *      2. force：如果强制提交/回滚（force 为 true），则无论是否有未提交的更改都需要提交或回滚。
         */
        return (!autoCommit && dirty) || force;
    }

    @Override
    public <T> T getMapper(Class<T> mapperClass) {
        return configuration.getMapper(mapperClass, this);
    }

    @Override
    public Configuration getConfiguration() {
        return configuration;
    }
}
